/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.brainy.perseu.generic.dao;

import br.com.brainy.perseu.generic.exeptions.BankException;
import br.com.brainy.perseu.generic.interfaces.IGenericDAO;
import br.com.brainy.perseu.generic.util.HibernateUtil;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

/**
 * 
 * This class is responsable for implamentation od all methods of the IGenercDAO
 *
 * @author Luiz Segundo
 */
public class GenericDAO<T extends Serializable> implements IGenericDAO<T> {

        protected static Session session = null;
        protected Transaction transaction = null;
        T t;

        public GenericDAO(T t) {
                this.t = t;
                session = HibernateUtil.getSessionFactory().openSession();
        }

        /**
         * This method is responsible to open the sesseio and begin the transaction.
         * If I don't use it, we'll need write this lines in all methods
         * 
         * 
         * @author Luiz Segundo
         */
        public void beginSession() {
                if (session == null || !session.isOpen()) {
                        session = HibernateUtil.getSessionFactory().openSession();
                }

        }

        /**
         * 
         * This method is responsable for begin the transaction of the DB.
         * 
         * @author Luiz Segundo
         */
        public void beginTransaction() {
                transaction = session.beginTransaction();
        }

        /**
         *
         * This method is responsable for finish all connections with the DB.
         *
         * @author Luiz Segundo
         */
        public void finilizeSession() {
                if (session.isOpen()) {
                        session.close();
                }
        }

        /**
         * 
         * This method is responsable for finish all connections and transactions with the DB.
         * If I don't use it, we'll need write this lines in all methods
         * 
         * @author Luiz Segundo
         */
        public void finalizeHibernate() {
                if (((transaction != null) && (session != null))) {
                        if (transaction.isActive() && session.isOpen()) {
                                transaction.commit();
                        }
                }
        }

        /**
         * 
         * This method is responsable for add any object at the DB.
         * 
         * 
         * @param t any object
         * @return true if the "insert" was done correct.
         * @throws BankException for any problem and the "catch" do a rollback in the DB.
         */
        @Override
        public boolean addObject(T t) throws BankException {
                try {
                        this.beginTransaction();
                        session.merge(t);
                        transaction.commit();
                } catch (Exception e) {
                        transaction.rollback();
                        System.out.println(e.getMessage());
                        throw new BankException("Some error has occurred in add metod on 'addObject'");
                }finally{
                        this.finilizeSession();
                }
                return true;

        }

        /**
         * 
         * This method is responsable for remove any object at the DB.
         * 
         * 
         * @param t any object
         * @return true if the "delete" was done correct.
         * @throws BankException for any problem and the "catch" do a rollback in the DB.
         */
        @Override
        public boolean removeObject(T t) throws BankException {
                try {
                        this.beginTransaction();
                        session.delete(t);
                        transaction.commit();
                } catch (Exception e) {
                        transaction.rollback();
                        throw new BankException("Some error has occurred in add metod on 'removeObject'");
                }finally{
                        this.finilizeSession();
                }
                return true;
        }

        /**
         * 
         * This method is responsable for "update" any object at the DB.
         * 
         * 
         * @param t any object
         * @return true if the "update" was done correct.
         * @throws BankException for any problem and the "catch" do a rollback in the DB.
         */
        @Override
        public boolean updateObject(T t) throws BankException {
                try {
                        this.beginTransaction();
                        session.merge(t);
                        transaction.commit();
                } catch (Exception e) {
                        transaction.rollback();
                        throw new BankException("Some error has occurred in add metod on 'updateObject'");
                } finally {
                        this.finilizeSession();
                }
                return true;
        }

        /**
         * 
         * Search a object for name and last name.
         * 
         * @param name
         * @param lastName
         * @param t
         * @return a object for the attribute name.
         * @throws BankException 
         */
        @Override
        public T searchObjectForNameLastName(String name, String lastName) throws BankException {
                try {
                        this.beginTransaction();
                        Criteria c = session.createCriteria(t.getClass());
                        c.add(Restrictions.ilike("nome", name));
                        c.add(Restrictions.ilike("sobrenome", lastName));
                        t = (T) c.uniqueResult();
                        return t;
                } catch (Exception e) {
                        transaction.rollback();
                        throw new BankException("Erro ao tentar buscar por Nome" + t.getClass());
                }finally{
                        this.finilizeSession();
                }
        }

        /**
         * 
         * Search a object for name .
         * 
         * @param name
         * @param lastName
         * @param t
         * @return a object for the attribute name.
         * @throws BankException 
         */
        @Override
        public List<T> searchObjectForName(String name) throws BankException {
                try {
                        this.beginTransaction();
                        Criteria c = session.createCriteria(t.getClass());
                        c.add(Restrictions.ilike("primeiroNome", name, MatchMode.ANYWHERE));
                        return c.list();
                } catch (Exception e) {
                        transaction.rollback();
                        throw new BankException("Erro ao tentar buscar por Nome" + t.getClass());
                }finally{
                        this.finilizeSession();
                }
        }

        /**
         * 
         * 
         * 
         * 
         * @param atributo
         * @param busca
         * @param t
         * @return A list of object for the any attribute 
         * @throws BankException 
         */
        @Override
        public List<T> searchForAttributeString(String attribute, String search) throws BankException {
                try {
                        this.beginTransaction();
                        Criteria c = session.createCriteria(t.getClass());
                        c.add(Restrictions.ilike(attribute, "%" + search + "%"));
                        if (c.list() == null) {
                                throw new BankException("Não foi encontrado");
                        }
                        return c.list();
                } catch (Exception e) {
                        transaction.rollback();
                        throw new BankException("Erro ao tentar buscar Lista de " + attribute + t.getClass());
                }finally{
                        this.finilizeSession();
                }
        }

        @Override
        public T searchObjectForID(Long id) throws BankException {
                try {
                        this.beginTransaction();
                        Criteria c = session.createCriteria(t.getClass());
                        c.add(Restrictions.ilike("id", id));
                        if (c.list() == null) {
                                throw new BankException("Não foi encontrado");
                        }
                        return (T) c.uniqueResult();
                } catch (Exception e) {
                        transaction.rollback();
                        throw new BankException("Erro ao tentar buscar objeto" + t.getClass());
                }finally{
                        this.finilizeSession();
                }
        }

        @Override
        public List<T> listAll() {
                Criteria c = session.createCriteria(t.getClass());
                return c.list();
        }

       
}
